import unittest
import memory, processor



class TestMemory(unittest.TestCase):


    def setUp(self):
        self.memory = memory.Memory(0x10000)

    
    def test_load(self):
        self.memory.load(0x1000, [0x01, 0x02, 0x03])
        self.assertEqual(self.memory[0x1000], 0x01)
        self.assertEqual(self.memory[0x1001], 0x02)
        self.assertEqual(self.memory[0x1002], 0x03)


    def test_write(self):
        self.memory[0x1000] = 0x11
        self.memory[0x1001] = 0x12
        self.memory[0x1002] = 0x13
        self.assertEqual(self.memory[0x1000], 0x11)
        self.assertEqual(self.memory[0x1001], 0x12)
        self.assertEqual(self.memory[0x1002], 0x13)



class TestLoadStoreOperations(unittest.TestCase):


    def setUp(self):
        self.memory = memory.Memory(0x10000)
        self.processor = processor.CPU(self.memory)
        self.memory.load(0x1000, [0x00, 0x01, 0x7F, 0x80, 0xFF])


    def test_LDA(self):
        self.processor.LDA(0x1000)
        self.assertEqual(self.processor.accumulator, 0x00)
        self.assertEqual(self.processor.flags.negative, False)
        self.assertEqual(self.processor.flags.zero, True)
        self.processor.LDA(0x1001)
        self.assertEqual(self.processor.accumulator, 0x01)
        self.assertEqual(self.processor.flags.negative, False)
        self.assertEqual(self.processor.flags.zero, False)
        self.processor.LDA(0x1002)
        self.assertEqual(self.processor.accumulator, 0x7F)
        self.assertEqual(self.processor.flags.negative, False)
        self.assertEqual(self.processor.flags.zero, False)
        self.processor.LDA(0x1003)
        self.assertEqual(self.processor.accumulator, 0x80)
        self.assertEqual(self.processor.flags.negative, True)
        self.assertEqual(self.processor.flags.zero, False)
        self.processor.LDA(0x1004)
        self.assertEqual(self.processor.accumulator, 0xFF)
        self.assertEqual(self.processor.flags.negative, True)
        self.assertEqual(self.processor.flags.zero, False)
        
    
    def test_LDX(self):
        self.processor.LDX(0x1000)
        self.assertEqual(self.processor.x_register, 0x00)
        self.assertEqual(self.processor.flags.negative, False)
        self.assertEqual(self.processor.flags.zero, True)
        self.processor.LDX(0x1001)
        self.assertEqual(self.processor.x_register, 0x01)
        self.assertEqual(self.processor.flags.negative, False)
        self.assertEqual(self.processor.flags.zero, False)
        self.processor.LDX(0x1002)
        self.assertEqual(self.processor.x_register, 0x7F)
        self.assertEqual(self.processor.flags.negative, False)
        self.assertEqual(self.processor.flags.zero, False)
        self.processor.LDX(0x1003)
        self.assertEqual(self.processor.x_register, 0x80)
        self.assertEqual(self.processor.flags.negative, True)
        self.assertEqual(self.processor.flags.zero, False)
        self.processor.LDX(0x1004)
        self.assertEqual(self.processor.x_register, 0xFF)
        self.assertEqual(self.processor.flags.negative, True)
        self.assertEqual(self.processor.flags.zero, False)


    def test_LDY(self):
        self.processor.LDY(0x1000)
        self.assertEqual(self.processor.y_register, 0x00)
        self.assertEqual(self.processor.flags.negative, False)
        self.assertEqual(self.processor.flags.zero, True)
        self.processor.LDY(0x1001)
        self.assertEqual(self.processor.y_register, 0x01)
        self.assertEqual(self.processor.flags.negative, False)
        self.assertEqual(self.processor.flags.zero, False)
        self.processor.LDY(0x1002)
        self.assertEqual(self.processor.y_register, 0x7F)
        self.assertEqual(self.processor.flags.negative, False)
        self.assertEqual(self.processor.flags.zero, False)
        self.processor.LDY(0x1003)
        self.assertEqual(self.processor.y_register, 0x80)
        self.assertEqual(self.processor.flags.negative, True)
        self.assertEqual(self.processor.flags.zero, False)
        self.processor.LDY(0x1004)
        self.assertEqual(self.processor.y_register, 0xFF)
        self.assertEqual(self.processor.flags.negative, True)
        self.assertEqual(self.processor.flags.zero, False)


    def test_STA(self):
        self.processor.accumulator = 0x37
        self.processor.STA(0x2000)
        self.assertEqual(self.memory[0x2000], 0x37)


    def test_STX(self):
        self.processor.x_register = 0x38
        self.processor.STX(0x2000)
        self.assertEqual(self.memory[0x2000], 0x38)


    def test_STY(self):
        self.processor.y_register = 0x39
        self.processor.STY(0x2000)
        self.assertEqual(self.memory[0x2000], 0x39)



class TestRegisterTransferOperations(unittest.TestCase):


    def setUp(self):
        self.memory = memory.Memory(0x10000)
        self.processor = processor.CPU(self.memory)


    def test_TAX(self):
        self.processor.accumulator = 0x00
        self.processor.TAX()
        self.assertEqual(self.processor.x_register, 0x00)
        self.assertEqual(self.processor.flags.negative, False)
        self.assertEqual(self.processor.flags.zero, True)
        self.processor.accumulator = 0x01
        self.processor.TAX()
        self.assertEqual(self.processor.x_register, 0x01)
        self.assertEqual(self.processor.flags.negative, False)
        self.assertEqual(self.processor.flags.zero, False)
        self.processor.accumulator = 0xFF
        self.processor.TAX()
        self.assertEqual(self.processor.x_register, 0xFF)
        self.assertEqual(self.processor.flags.negative, True)
        self.assertEqual(self.processor.flags.zero, False)


    def test_TAY(self):
        self.processor.accumulator = 0x00
        self.processor.TAY()
        self.assertEqual(self.processor.y_register, 0x00)
        self.assertEqual(self.processor.flags.negative, False)
        self.assertEqual(self.processor.flags.zero, True)
        self.processor.accumulator = 0x01
        self.processor.TAY()
        self.assertEqual(self.processor.y_register, 0x01)
        self.assertEqual(self.processor.flags.negative, False)
        self.assertEqual(self.processor.flags.zero, False)
        self.processor.accumulator = 0xFF
        self.processor.TAY()
        self.assertEqual(self.processor.y_register, 0xFF)
        self.assertEqual(self.processor.flags.negative, True)
        self.assertEqual(self.processor.flags.zero, False)


    def test_TXA(self):
        self.processor.x_register = 0x00
        self.processor.TXA()
        self.assertEqual(self.processor.accumulator, 0x00)
        self.assertEqual(self.processor.flags.negative, False)
        self.assertEqual(self.processor.flags.zero, True)
        self.processor.x_register = 0x01
        self.processor.TXA()
        self.assertEqual(self.processor.accumulator, 0x01)
        self.assertEqual(self.processor.flags.negative, False)
        self.assertEqual(self.processor.flags.zero, False)
        self.processor.x_register = 0xFF
        self.processor.TXA()
        self.assertEqual(self.processor.accumulator, 0xFF)
        self.assertEqual(self.processor.flags.negative, True)
        self.assertEqual(self.processor.flags.zero, False)


    def test_TYA(self):
        self.processor.y_register = 0x00
        self.processor.TYA()
        self.assertEqual(self.processor.accumulator, 0x00)
        self.assertEqual(self.processor.flags.negative, False)
        self.assertEqual(self.processor.flags.zero, True)
        self.processor.y_register = 0x01
        self.processor.TYA()
        self.assertEqual(self.processor.accumulator, 0x01)
        self.assertEqual(self.processor.flags.negative, False)
        self.assertEqual(self.processor.flags.zero, False)
        self.processor.y_register = 0xFF
        self.processor.TYA()
        self.assertEqual(self.processor.accumulator, 0xFF)
        self.assertEqual(self.processor.flags.negative, True)
        self.assertEqual(self.processor.flags.zero, False)



class TestStackOperations(unittest.TestCase):


    def setUp(self):
        self.memory = memory.Memory(0x10000)
        self.processor = processor.CPU(self.memory)


    def test_TSX(self):
        s = self.processor.stack_pointer
        self.processor.TSX()
        self.assertEqual(self.processor.x_register, s)
        # @@@ check NZ?


    def test_TXS(self):
        x = self.processor.x_register
        self.processor.TXS()
        self.assertEqual(self.processor.stack_pointer, x)


    def test_PHA_and_PLA(self):
        self.processor.accumulator = 0x00
        self.processor.PHA()
        self.processor.accumulator = 0x01
        self.processor.PHA()
        self.processor.accumulator = 0xFF
        self.processor.PHA()
        self.assertEqual(self.processor.accumulator, 0xFF)
        self.assertEqual(self.processor.flags.zero, False)
        self.assertEqual(self.processor.flags.negative, False)
        self.processor.PLA()
        self.assertEqual(self.processor.accumulator, 0xFF)
        self.assertEqual(self.processor.flags.zero, False)
        self.assertEqual(self.processor.flags.negative, True)
        self.processor.PLA()
        self.assertEqual(self.processor.accumulator, 0x01)
        self.assertEqual(self.processor.flags.zero, False)
        self.assertEqual(self.processor.flags.negative, False)
        self.processor.PLA()
        self.assertEqual(self.processor.accumulator, 0x00)
        self.assertEqual(self.processor.flags.zero, True)
        self.assertEqual(self.processor.flags.negative, False)


    def test_PHP_and_PLP(self):
        p = self.processor.processor_status
        self.processor.PHP()
        self.processor.processor_status = 0xFF
        self.processor.PLP()
        self.assertEqual(self.processor.processor_status, p)





class TestLogicalOperations(unittest.TestCase):


    def setUp(self):
        self.memory = memory.Memory(0x10000)
        self.processor = processor.CPU(self.memory)
    

    def test_AND(self):
        self.memory[0x1000] = 0x37
        self.processor.accumulator = 0x34
        self.processor.AND(0x1000)
        self.assertEqual(self.processor.accumulator, 0x34)
        self.assertEqual(self.processor.flags.zero, False)
        self.assertEqual(self.processor.flags.negative, False)
        self.processor.accumulator = 0x40
        self.processor.AND(0x1000)
        self.assertEqual(self.processor.accumulator, 0x00)
        self.assertEqual(self.processor.flags.zero, True)
        self.assertEqual(self.processor.flags.negative, False)


    def test_EOR(self):
        self.memory[0x1000] = 0x37
        self.processor.accumulator = 0x34
        self.processor.EOR(0x1000)
        self.assertEqual(self.processor.accumulator, 0x03)
        self.assertEqual(self.processor.flags.zero, False)
        self.assertEqual(self.processor.flags.negative, False)
        self.processor.accumulator = 0x90
        self.processor.EOR(0x1000)
        self.assertEqual(self.processor.accumulator, 0xA7)
        self.assertEqual(self.processor.flags.zero, False)
        self.assertEqual(self.processor.flags.negative, True)
        self.processor.accumulator = 0x37
        self.processor.EOR(0x1000)
        self.assertEqual(self.processor.accumulator, 0x00)
        self.assertEqual(self.processor.flags.zero, True)
        self.assertEqual(self.processor.flags.negative, False)


    def test_ORA(self):
        self.memory[0x1000] = 0x37
        self.processor.accumulator = 0x34
        self.processor.ORA(0x1000)
        self.assertEqual(self.processor.accumulator, 0x37)
        self.assertEqual(self.processor.flags.zero, False)
        self.assertEqual(self.processor.flags.negative, False)
        self.processor.accumulator = 0x90
        self.processor.ORA(0x1000)
        self.assertEqual(self.processor.accumulator, 0xB7)
        self.assertEqual(self.processor.flags.zero, False)
        self.assertEqual(self.processor.flags.negative, True)
        self.processor.accumulator = 0x00
        self.processor.ORA(0x1001)
        self.assertEqual(self.processor.accumulator, 0x00)
        self.assertEqual(self.processor.flags.zero, True)
        self.assertEqual(self.processor.flags.negative, False)


    def test_BIT(self):
        self.memory[0x1000] = 0x00
        self.processor.accumulator = 0x00
        self.processor.BIT(0x1000)
        self.assertEqual(self.processor.flags.overflow, False)
        self.assertEqual(self.processor.flags.negative, False)
        self.assertEqual(self.processor.flags.zero, True)
        self.memory[0x1000] = 0x40
        self.processor.accumulator = 0x00
        self.processor.BIT(0x1000)
        self.assertEqual(self.processor.flags.overflow, True)
        self.assertEqual(self.processor.flags.negative, False)
        self.assertEqual(self.processor.flags.zero, True)
        self.memory[0x1000] = 0x80
        self.processor.accumulator = 0x00
        self.processor.BIT(0x1000)
        self.assertEqual(self.processor.flags.overflow, False)
        self.assertEqual(self.processor.flags.negative, True)
        self.assertEqual(self.processor.flags.zero, True)
        self.memory[0x1000] = 0xC0
        self.processor.accumulator = 0x00
        self.processor.BIT(0x1000)
        self.assertEqual(self.processor.flags.overflow, True)
        self.assertEqual(self.processor.flags.negative, True)
        self.assertEqual(self.processor.flags.zero, True)
        self.memory[0x1000] = 0xC0
        self.processor.accumulator = 0xC0
        self.processor.BIT(0x1000)
        self.assertEqual(self.processor.flags.overflow, True)
        self.assertEqual(self.processor.flags.negative, True)
        self.assertEqual(self.processor.flags.zero, False)



class TestArithmeticOperations(unittest.TestCase):


    def setUp(self):
        self.memory = memory.Memory(0x10000)
        self.processor = processor.CPU(self.memory)


    def test_ADC_without_BCD(self):

        ## test cases from http://www.6502.org/tutorials/vflag.html
    
        # 1 + 1 = 2  (C = 0; V = 0)
        self.processor.flags.carry = False
        self.processor.accumulator = 0x01
        self.memory[0x1000] = 0x01
        self.processor.ADC(0x1000)
        self.assertEqual(self.processor.accumulator, 0x02)
        self.assertEqual(self.processor.flags.carry, False)
        self.assertEqual(self.processor.flags.overflow, False)

        # 1 + -1 = 0  (C = 1; V = 0)
        self.processor.flags.carry = False
        self.processor.accumulator = 0x01
        self.memory[0x1000] = 0xFF
        self.processor.ADC(0x1000)
        self.assertEqual(self.processor.accumulator, 0x00)
        self.assertEqual(self.processor.flags.carry, True)
        self.assertEqual(self.processor.flags.overflow, False)

        # 127 + 1 = 128  (C = 0; V = 1)
        self.processor.flags.carry = False
        self.processor.accumulator = 0x7F
        self.memory[0x1000] = 0x01
        self.processor.ADC(0x1000)
        self.assertEqual(self.processor.accumulator, 0x80) # @@@
        self.assertEqual(self.processor.flags.carry, False)
        self.assertEqual(self.processor.flags.overflow, True)

        # -128 + -1 = -129  (C = 1; V = 1)
        self.processor.flags.carry = False
        self.processor.accumulator = 0x80
        self.memory[0x1000] = 0xFF
        self.processor.ADC(0x1000)
        self.assertEqual(self.processor.accumulator, 0x7F) # @@@
        self.assertEqual(self.processor.flags.carry, True)
        self.assertEqual(self.processor.flags.overflow, True)

        # 63 + 64 + 1 = 128  (C = 0; V = 1)
        self.processor.flags.carry = True
        self.processor.accumulator = 0x3F
        self.memory[0x1000] = 0x40
        self.processor.ADC(0x1000)
        self.assertEqual(self.processor.accumulator, 0x80)
        self.assertEqual(self.processor.flags.carry, False)
        self.assertEqual(self.processor.flags.overflow, True)

        
        
    def test_SBC_without_BCD(self):
        self.processor.accumulator = 0x02
        self.memory[0x1000] = 0x01
        self.processor.SBC(0x1000)
        self.assertEqual(self.processor.accumulator, 0x00)
        self.assertEqual(self.processor.flags.carry, True)
        self.assertEqual(self.processor.flags.overflow, False)

        self.processor.accumulator = 0x01
        self.memory[0x1000] = 0x02
        self.processor.SBC(0x1000)
        self.assertEqual(self.processor.accumulator, 0xFF)
        self.assertEqual(self.processor.flags.carry, False)
        self.assertEqual(self.processor.flags.overflow, False) # @@@

        ## test cases from http://www.6502.org/tutorials/vflag.html
    
        # 0 - 1 = -1  (V = 0)
        self.processor.flags.carry = True
        self.processor.accumulator = 0x00
        self.memory[0x1000] = 0x01
        self.processor.SBC(0x1000)
        self.assertEqual(self.processor.accumulator, 0xFF)
        self.assertEqual(self.processor.flags.carry, False)
        self.assertEqual(self.processor.flags.overflow, False) # @@@
        
        # -128 - 1 = -129  (V = 1)
        self.processor.flags.carry = True
        self.processor.accumulator = 0x80
        self.memory[0x1000] = 0x01
        self.processor.SBC(0x1000)
        self.assertEqual(self.processor.accumulator, 0x7F)
        self.assertEqual(self.processor.flags.carry, True)
        self.assertEqual(self.processor.flags.overflow, True)
    
        # 127 - -1 = 128  (V = 1)
        self.processor.flags.carry = True
        self.processor.accumulator = 0x7F
        self.memory[0x1000] = 0xFF
        self.processor.SBC(0x1000)
        self.assertEqual(self.processor.accumulator, 0x80)
        self.assertEqual(self.processor.flags.carry, False)
        self.assertEqual(self.processor.flags.overflow, True)
        
        # -64 -64 -1 = -129  (V = 1)
        self.processor.flags.carry = False
        self.processor.accumulator = 0xC0
        self.memory[0x1000] = 0x40
        self.processor.SBC(0x1000)
        self.assertEqual(self.processor.accumulator, 0x7F)
        self.assertEqual(self.processor.flags.carry, True)
        self.assertEqual(self.processor.flags.overflow, True) # @@@

    
    ## @@@ BCD versions still to do


    def test_CMP(self):
        self.processor.accumulator = 0x0A
        self.memory[0x1000] = 0x09
        self.processor.CMP(0x1000)
        self.assertEqual(self.processor.flags.negative, False)
        self.assertEqual(self.processor.flags.zero, False)
        self.assertEqual(self.processor.flags.carry, True)

        self.processor.accumulator = 0x0A
        self.memory[0x1000] = 0x0B
        self.processor.CMP(0x1000)
        self.assertEqual(self.processor.flags.negative, True)
        self.assertEqual(self.processor.flags.zero, False)
        self.assertEqual(self.processor.flags.carry, False)

        self.processor.accumulator = 0x0A
        self.memory[0x1000] = 0x0A
        self.processor.CMP(0x1000)
        self.assertEqual(self.processor.flags.negative, False)
        self.assertEqual(self.processor.flags.zero, True)
        self.assertEqual(self.processor.flags.carry, True)

        self.processor.accumulator = 0xA0
        self.memory[0x1000] = 0x0A
        self.processor.CMP(0x1000)
        self.assertEqual(self.processor.flags.negative, True)
        self.assertEqual(self.processor.flags.zero, False)
        self.assertEqual(self.processor.flags.carry, True)

        self.processor.accumulator = 0x0A
        self.memory[0x1000] = 0xA0
        self.processor.CMP(0x1000)
        self.assertEqual(self.processor.flags.negative, False) # @@@
        self.assertEqual(self.processor.flags.zero, False)
        self.assertEqual(self.processor.flags.carry, False)
        
        
    def test_CPX(self):
        self.processor.x_register = 0x0A
        self.memory[0x1000] = 0x09
        self.processor.CPX(0x1000)
        self.assertEqual(self.processor.flags.negative, False)
        self.assertEqual(self.processor.flags.zero, False)
        self.assertEqual(self.processor.flags.carry, True)

        self.processor.x_register = 0x0A
        self.memory[0x1000] = 0x0B
        self.processor.CPX(0x1000)
        self.assertEqual(self.processor.flags.negative, True)
        self.assertEqual(self.processor.flags.zero, False)
        self.assertEqual(self.processor.flags.carry, False)

        self.processor.x_register = 0x0A
        self.memory[0x1000] = 0x0A
        self.processor.CPX(0x1000)
        self.assertEqual(self.processor.flags.negative, False)
        self.assertEqual(self.processor.flags.zero, True)
        self.assertEqual(self.processor.flags.carry, True)

        self.processor.x_register = 0xA0
        self.memory[0x1000] = 0x0A
        self.processor.CPX(0x1000)
        self.assertEqual(self.processor.flags.negative, True)
        self.assertEqual(self.processor.flags.zero, False)
        self.assertEqual(self.processor.flags.carry, True)

        self.processor.x_register = 0x0A
        self.memory[0x1000] = 0xA0
        self.processor.CPX(0x1000)
        self.assertEqual(self.processor.flags.negative, False) # @@@
        self.assertEqual(self.processor.flags.zero, False)
        self.assertEqual(self.processor.flags.carry, False)


    def test_CPY(self):
        self.processor.y_register = 0x0A
        self.memory[0x1000] = 0x09
        self.processor.CPY(0x1000)
        self.assertEqual(self.processor.flags.negative, False)
        self.assertEqual(self.processor.flags.zero, False)
        self.assertEqual(self.processor.flags.carry, True)

        self.processor.y_register = 0x0A
        self.memory[0x1000] = 0x0B
        self.processor.CPY(0x1000)
        self.assertEqual(self.processor.flags.negative, True)
        self.assertEqual(self.processor.flags.zero, False)
        self.assertEqual(self.processor.flags.carry, False)

        self.processor.y_register = 0x0A
        self.memory[0x1000] = 0x0A
        self.processor.CPY(0x1000)
        self.assertEqual(self.processor.flags.negative, False)
        self.assertEqual(self.processor.flags.zero, True)
        self.assertEqual(self.processor.flags.carry, True)

        self.processor.y_register = 0xA0
        self.memory[0x1000] = 0x0A
        self.processor.CPY(0x1000)
        self.assertEqual(self.processor.flags.negative, True)
        self.assertEqual(self.processor.flags.zero, False)
        self.assertEqual(self.processor.flags.carry, True)

        self.processor.y_register = 0x0A
        self.memory[0x1000] = 0xA0
        self.processor.CPY(0x1000)
        self.assertEqual(self.processor.flags.negative, False) # @@@
        self.assertEqual(self.processor.flags.zero, False)
        self.assertEqual(self.processor.flags.carry, False)



class TestIncrementDecrementOperations(unittest.TestCase):


    def setUp(self):
        self.memory = memory.Memory(0x10000)
        self.processor = processor.CPU(self.memory)


    def test_INC(self):
        self.memory[0x1000] = 0x00
        self.processor.INC(0x1000)
        self.assertEqual(self.memory[0x1000], 0x01)
        self.assertEqual(self.processor.flags.negative, False)
        self.assertEqual(self.processor.flags.zero, False)
        self.memory[0x1000] = 0x7F
        self.processor.INC(0x1000)
        self.assertEqual(self.memory[0x1000], 0x80)
        self.assertEqual(self.processor.flags.negative, True)
        self.assertEqual(self.processor.flags.zero, False)
        self.memory[0x1000] = 0xFF
        self.processor.INC(0x1000)
        self.assertEqual(self.memory[0x1000], 0x00)
        self.assertEqual(self.processor.flags.negative, False)
        self.assertEqual(self.processor.flags.zero, True)


    def test_INX(self):
        self.processor.x_register = 0x00
        self.processor.INX()
        self.assertEqual(self.processor.x_register, 0x01)
        self.assertEqual(self.processor.flags.negative, False)
        self.assertEqual(self.processor.flags.zero, False)
        self.processor.x_register = 0x7F
        self.processor.INX()
        self.assertEqual(self.processor.x_register, 0x80)
        self.assertEqual(self.processor.flags.negative, True)
        self.assertEqual(self.processor.flags.zero, False)
        self.processor.x_register = 0xFF
        self.processor.INX()
        self.assertEqual(self.processor.x_register, 0x00)
        self.assertEqual(self.processor.flags.negative, False)
        self.assertEqual(self.processor.flags.zero, True)


    def test_INY(self):
        self.processor.y_register = 0x00
        self.processor.INY()
        self.assertEqual(self.processor.y_register, 0x01)
        self.assertEqual(self.processor.flags.negative, False)
        self.assertEqual(self.processor.flags.zero, False)
        self.processor.y_register = 0x7F
        self.processor.INY()
        self.assertEqual(self.processor.y_register, 0x80)
        self.assertEqual(self.processor.flags.negative, True)
        self.assertEqual(self.processor.flags.zero, False)
        self.processor.y_register = 0xFF
        self.processor.INY()
        self.assertEqual(self.processor.y_register, 0x00)
        self.assertEqual(self.processor.flags.negative, False)
        self.assertEqual(self.processor.flags.zero, True)


    def test_DEC(self):
        self.memory[0x1000] = 0x01
        self.processor.DEC(0x1000)
        self.assertEqual(self.memory[0x1000], 0x00)
        self.assertEqual(self.processor.flags.negative, False)
        self.assertEqual(self.processor.flags.zero, True)
        self.memory[0x1000] = 0x80
        self.processor.DEC(0x1000)
        self.assertEqual(self.memory[0x1000], 0x7F)
        self.assertEqual(self.processor.flags.negative, False)
        self.assertEqual(self.processor.flags.zero, False)
        self.memory[0x1000] = 0x00
        self.processor.DEC(0x1000)
        self.assertEqual(self.memory[0x1000], 0xFF)
        self.assertEqual(self.processor.flags.negative, True)
        self.assertEqual(self.processor.flags.zero, False)


    def test_DEX(self):
        self.processor.x_register = 0x01
        self.processor.DEX()
        self.assertEqual(self.processor.x_register, 0x00)
        self.assertEqual(self.processor.flags.negative, False)
        self.assertEqual(self.processor.flags.zero, True)
        self.processor.x_register = 0x80
        self.processor.DEX()
        self.assertEqual(self.processor.x_register, 0x7F)
        self.assertEqual(self.processor.flags.negative, False)
        self.assertEqual(self.processor.flags.zero, False)
        self.processor.x_register = 0x00
        self.processor.DEX()
        self.assertEqual(self.processor.x_register, 0xFF)
        self.assertEqual(self.processor.flags.negative, True)
        self.assertEqual(self.processor.flags.zero, False)


    def test_DEY(self):
        self.processor.y_register = 0x01
        self.processor.DEY()
        self.assertEqual(self.processor.y_register, 0x00)
        self.assertEqual(self.processor.flags.negative, False)
        self.assertEqual(self.processor.flags.zero, True)
        self.processor.y_register = 0x80
        self.processor.DEY()
        self.assertEqual(self.processor.y_register, 0x7F)
        self.assertEqual(self.processor.flags.negative, False)
        self.assertEqual(self.processor.flags.zero, False)
        self.processor.y_register = 0x00
        self.processor.DEY()
        self.assertEqual(self.processor.y_register, 0xFF)
        self.assertEqual(self.processor.flags.negative, True)
        self.assertEqual(self.processor.flags.zero, False)



class TestShiftOperations(unittest.TestCase):


    def setUp(self):
        self.memory = memory.Memory(0x10000)
        self.processor = processor.CPU(self.memory)


    def test_ASL(self):
        self.processor.accumulator = 0x01
        self.processor.ASL()
        self.assertEqual(self.processor.accumulator, 0x02)
        self.assertEqual(self.processor.flags.negative, False)
        self.assertEqual(self.processor.flags.zero, False)
        self.assertEqual(self.processor.flags.carry, False)
        self.memory[0x1000] = 0x02
        self.processor.ASL(0x1000)
        self.assertEqual(self.memory[0x1000], 0x04)
        self.assertEqual(self.processor.flags.negative, False)
        self.assertEqual(self.processor.flags.zero, False)
        self.assertEqual(self.processor.flags.carry, False)
        self.processor.accumulator = 0x80
        self.processor.ASL()
        self.assertEqual(self.processor.accumulator, 0x00)
        self.assertEqual(self.processor.flags.negative, False)
        self.assertEqual(self.processor.flags.zero, False) # @@@
        self.assertEqual(self.processor.flags.carry, True)


    def test_LSR(self):
        self.processor.accumulator = 0x01
        self.processor.LSR()
        self.assertEqual(self.processor.accumulator, 0x00)
        self.assertEqual(self.processor.flags.negative, False)
        self.assertEqual(self.processor.flags.zero, True)
        self.assertEqual(self.processor.flags.carry, True)
        self.memory[0x1000] = 0x01
        self.processor.LSR(0x1000)
        self.assertEqual(self.memory[0x1000], 0x00)
        self.assertEqual(self.processor.flags.negative, False)
        self.assertEqual(self.processor.flags.zero, True)
        self.assertEqual(self.processor.flags.carry, True)
        self.processor.accumulator = 0x80
        self.processor.LSR()
        self.assertEqual(self.processor.accumulator, 0x40)
        self.assertEqual(self.processor.flags.negative, False)
        self.assertEqual(self.processor.flags.zero, False)
        self.assertEqual(self.processor.flags.carry, False)


    def test_ROL(self):
        self.processor.flags.carry = False
        self.processor.accumulator = 0x80
        self.processor.ROL()
        self.assertEqual(self.processor.accumulator, 0x00)
        self.assertEqual(self.processor.flags.negative, False)
        self.assertEqual(self.processor.flags.zero, False) # @@@
        self.assertEqual(self.processor.flags.carry, True)
        self.processor.flags.carry = True
        self.processor.accumulator = 0x80
        self.processor.ROL()
        self.assertEqual(self.processor.accumulator, 0x01)
        self.assertEqual(self.processor.flags.negative, False)
        self.assertEqual(self.processor.flags.zero, False) # @@@
        self.assertEqual(self.processor.flags.carry, True)
        self.processor.flags.carry = False
        self.processor.memory[0x1000] = 0x80
        self.processor.ROL(0x1000)
        self.assertEqual(self.memory[0x1000], 0x00)
        self.assertEqual(self.processor.flags.negative, False)
        self.assertEqual(self.processor.flags.zero, False) # @@@
        self.assertEqual(self.processor.flags.carry, True)
        self.processor.flags.carry = True
        self.processor.memory[0x1000] = 0x80
        self.processor.ROL(0x1000)
        self.assertEqual(self.memory[0x1000], 0x01)
        self.assertEqual(self.processor.flags.negative, False)
        self.assertEqual(self.processor.flags.zero, False) # @@@
        self.assertEqual(self.processor.flags.carry, True)


    def test_ROR(self):
        self.processor.flags.carry = False
        self.processor.accumulator = 0x01
        self.processor.ROR()
        self.assertEqual(self.processor.accumulator, 0x00)
        self.assertEqual(self.processor.flags.negative, False)
        self.assertEqual(self.processor.flags.zero, True) # @@@
        self.assertEqual(self.processor.flags.carry, True)
        self.processor.flags.carry = True
        self.processor.accumulator = 0x01
        self.processor.ROR()
        self.assertEqual(self.processor.accumulator, 0x80)
        self.assertEqual(self.processor.flags.negative, True) # @@@
        self.assertEqual(self.processor.flags.zero, False) # @@@
        self.assertEqual(self.processor.flags.carry, True)
        self.processor.flags.carry = False
        self.processor.memory[0x1000] = 0x01
        self.processor.ROR(0x1000)
        self.assertEqual(self.memory[0x1000], 0x00)
        self.assertEqual(self.processor.flags.negative, False)
        self.assertEqual(self.processor.flags.zero, True) # @@@
        self.assertEqual(self.processor.flags.carry, True)
        self.processor.flags.carry = True
        self.processor.memory[0x1000] = 0x01
        self.processor.ROR(0x1000)
        self.assertEqual(self.memory[0x1000], 0x80)
        self.assertEqual(self.processor.flags.negative, True) # @@@
        self.assertEqual(self.processor.flags.zero, False) # @@@
        self.assertEqual(self.processor.flags.carry, True)



class TestJumpCallOperations(unittest.TestCase):


    def setUp(self):
        self.memory = memory.Memory(0x10000)
        self.processor = processor.CPU(self.memory)


    def test_JMP(self):
        self.processor.JMP(0x1000)
        self.assertEqual(self.processor.program_counter, 0x1000)


    def test_JSR(self):
        self.processor.program_counter = 0x1000
        self.processor.JSR(0x2000)
        self.assertEqual(self.processor.program_counter, 0x2000)
        self.assertEqual(self.memory[processor.STACK_PAGE + self.processor.stack_pointer + 1], 0xFF)
        self.assertEqual(self.memory[processor.STACK_PAGE + self.processor.stack_pointer + 2], 0x0F)
        
    
    def test_RTS(self):
        self.memory[processor.STACK_PAGE + 0xFF] = 0x12
        self.memory[processor.STACK_PAGE + 0xFE] = 0x33
        self.processor.stack_pointer = 0xFD
        self.processor.RTS()
        self.assertEqual(self.processor.program_counter, 0x1234)


    def test_JSR_and_RTS(self):
        self.processor.program_counter = 0x1000
        self.processor.JSR(0x2000)
        self.assertEqual(self.processor.program_counter, 0x2000)
        self.processor.RTS()
        self.assertEqual(self.processor.program_counter, 0x1000) # @@@



class TestBranchOperations(unittest.TestCase):


    def setUp(self):
        self.memory = memory.Memory(0x10000)
        self.processor = processor.CPU(self.memory)


    def test_BCC(self):
        self.processor.program_counter = 0x1000
        self.processor.flags.carry = True
        self.processor.BCC(0x2000)
        self.assertEqual(self.processor.program_counter, 0x1000)
        self.processor.program_counter = 0x1000
        self.processor.flags.carry = False
        self.processor.BCC(0x2000)
        self.assertEqual(self.processor.program_counter, 0x2000)


    def test_BCS(self):
        self.processor.program_counter = 0x1000
        self.processor.flags.carry = False
        self.processor.BCS(0x2000)
        self.assertEqual(self.processor.program_counter, 0x1000)
        self.processor.program_counter = 0x1000
        self.processor.flags.carry = True
        self.processor.BCS(0x2000)
        self.assertEqual(self.processor.program_counter, 0x2000)


    def test_BEQ(self):
        self.processor.program_counter = 0x1000
        self.processor.flags.zero = False
        self.processor.BEQ(0x2000)
        self.assertEqual(self.processor.program_counter, 0x1000)
        self.processor.program_counter = 0x1000
        self.processor.flags.zero = True
        self.processor.BEQ(0x2000)
        self.assertEqual(self.processor.program_counter, 0x2000)


    def test_BMI(self):
        self.processor.program_counter = 0x1000
        self.processor.flags.negative = False
        self.processor.BMI(0x2000)
        self.assertEqual(self.processor.program_counter, 0x1000)
        self.processor.program_counter = 0x1000
        self.processor.flags.negative = True
        self.processor.BMI(0x2000)
        self.assertEqual(self.processor.program_counter, 0x2000)


    def test_BNE(self):
        self.processor.program_counter = 0x1000
        self.processor.flags.zero = True
        self.processor.BNE(0x2000)
        self.assertEqual(self.processor.program_counter, 0x1000)
        self.processor.program_counter = 0x1000
        self.processor.flags.zero = False
        self.processor.BNE(0x2000)
        self.assertEqual(self.processor.program_counter, 0x2000)


    def test_BPL(self):
        self.processor.program_counter = 0x1000
        self.processor.flags.negative = True
        self.processor.BPL(0x2000)
        self.assertEqual(self.processor.program_counter, 0x1000)
        self.processor.program_counter = 0x1000
        self.processor.flags.negative = False
        self.processor.BPL(0x2000)
        self.assertEqual(self.processor.program_counter, 0x2000)


    def test_BVC(self):
        self.processor.program_counter = 0x1000
        self.processor.flags.overflow = True
        self.processor.BVC(0x2000)
        self.assertEqual(self.processor.program_counter, 0x1000)
        self.processor.program_counter = 0x1000
        self.processor.flags.overflow = False
        self.processor.BVC(0x2000)
        self.assertEqual(self.processor.program_counter, 0x2000)


    def test_BVS(self):
        self.processor.program_counter = 0x1000
        self.processor.flags.overflow = False
        self.processor.BVS(0x2000)
        self.assertEqual(self.processor.program_counter, 0x1000)
        self.processor.program_counter = 0x1000
        self.processor.flags.overflow = True
        self.processor.BVS(0x2000)
        self.assertEqual(self.processor.program_counter, 0x2000)



class TestStatusFlagOperations(unittest.TestCase):


    def setUp(self):
        self.memory = memory.Memory(0x10000)
        self.processor = processor.CPU(self.memory)


    def test_CLC(self):
        self.processor.flags.carry = True
        self.processor.CLC()
        self.assertEqual(self.processor.flags.carry, False)


    def test_CLD(self):
        self.processor.flags.decimal_mode = True
        self.processor.CLD()
        self.assertEqual(self.processor.flags.decimal_mode, False)


    def test_CLI(self):
        self.processor.flags.interrupt_disable = True
        self.processor.CLI()
        self.assertEqual(self.processor.flags.interrupt_disable, False)


    def test_CLV(self):
        self.processor.flags.overflow = True
        self.processor.CLV()
        self.assertEqual(self.processor.flags.overflow, False)


    def test_SEC(self):
        self.processor.flags.carry = False
        self.processor.SEC()
        self.assertEqual(self.processor.flags.carry, True)


    def test_SED(self):
        self.processor.flags.decimal_mode = False
        self.processor.SED()
        self.assertEqual(self.processor.flags.decimal_mode, True)


    def test_SEI(self):
        self.processor.flags.interrupt_disable = False
        self.processor.SEI()
        self.assertEqual(self.processor.flags.interrupt_disable, True)



class TestSystemFunctionOperations(unittest.TestCase):


    def setUp(self):
        self.memory = memory.Memory(0x10000)
        self.processor = processor.CPU(self.memory)


    def test_BRK(self):
        self.processor.program_counter = 0x1000
        self.memory[0xFFFE] = 0x00
        self.memory[0xFFFF] = 0x20
        status = self.processor.processor_status
        self.processor.BRK()
        self.assertEqual(self.processor.program_counter, 0x2000)
        self.assertEqual(self.processor.flags.break_command, True)
        self.assertEqual(self.memory[processor.STACK_PAGE + self.processor.stack_pointer + 1], status)
        self.assertEqual(self.memory[processor.STACK_PAGE + self.processor.stack_pointer + 2], 0x01)
        self.assertEqual(self.memory[processor.STACK_PAGE + self.processor.stack_pointer + 3], 0x10)


    def test_RTI(self):
        self.memory[processor.STACK_PAGE + 0xFF] = 0x12
        self.memory[processor.STACK_PAGE + 0xFE] = 0x33
        self.memory[processor.STACK_PAGE + 0xFD] = 0x20
        self.processor.stack_pointer = 0xFC
        self.processor.RTI()
        self.assertEqual(self.processor.program_counter, 0x1233)
        self.assertEqual(self.processor.processor_status, 0x20)


    def test_NOP(self):
        self.processor.NOP()        
        



if __name__ == "__main__":
    unittest.main()